#include "MainScene.h"
#include <QPainter>
#include <QRandomGenerator>

Bullet::Bullet(bool hero) : isHero(hero)
{
    if(isHero) {
        bullet.load(BULLET1_PATH);
        speed = BULLET_SPEED;
    } else {
        bullet.load(BULLET2_PATH);
        speed = -BULLET_SPEED;
    }
    isFree = true;
}

void Bullet::updatePosition()
{
    if(isFree) return;

    y += speed;

    if(y <= -bullet.height() || y >= GAME_HEIGHT) {
        isFree = true;
    }
}

Enemy::Enemy(int type) : type(type)
{
    explosion = new Explosion();
    switch(type) {
    case 1:
        enemy.load(ENEMY1_PATH);
        explosion->loadFrames({ENEMY1_DOWN1, ENEMY1_DOWN2, ENEMY1_DOWN3, ENEMY1_DOWN4});
        speed = ENEMY1_SPEED;
        health = 1;
        break;
    case 2:
        enemy.load(ENEMY2_PATH);
        explosion->loadFrames({ENEMY2_DOWN1, ENEMY2_DOWN2, ENEMY2_DOWN3, ENEMY2_DOWN4});
        speed = ENEMY2_SPEED;
        health = 3;
        break;
    case 3:
        enemy.load(ENEMY3_PATH);
        explosion->loadFrames({ENEMY3_DOWN1, ENEMY3_DOWN2, ENEMY3_DOWN3,
                               ENEMY3_DOWN4, ENEMY3_DOWN5, ENEMY3_DOWN6});
        speed = ENEMY3_SPEED;
        health = 5;
        break;
    }
    isFree = true;
}

Enemy::~Enemy()
{
    delete explosion;
}

void Enemy::updatePosition()
{
    if(isFree) return;

    if(explosion->isPlaying) {
        explosion->update();
        if(explosion->isFinished()) {
            isFree = true;
        }
        return;
    }

    y += speed;

    if(y >= GAME_HEIGHT) {
        isFree = true;
    }
}

void Enemy::down()
{
    if(!explosion->isPlaying) {
        explosion->play();
    }
}

Hero::Hero()
{
    hero.load(HERO_PATH);
    explosion = new Explosion();
    explosion->loadFrames({HERO_DOWN1, HERO_DOWN2, HERO_DOWN3, HERO_DOWN4});
    x = GAME_WIDTH * 0.5 - hero.width() * 0.5;
    y = GAME_HEIGHT - hero.height() - 50;
    speed = HERO_SPEED;
    rect.setWidth(hero.width());
    rect.setHeight(hero.height());
    rect.moveTo(x, y);
}

Hero::~Hero()
{
    delete explosion;
}

void Hero::updatePosition()
{
    if(explosion->isPlaying) {
        explosion->update();
        return;
    }

    rect.moveTo(x, y);
}

void Hero::down()
{
    if(!explosion->isPlaying) {
        explosion->play();
    }
}

MainScene::MainScene(QWidget *parent) : QWidget(parent)
{
    initScene();
    playGame();
}

MainScene::~MainScene()
{
}

void MainScene::initScene()
{
    setFixedSize(GAME_WIDTH, GAME_HEIGHT);
    setWindowTitle(GAME_TITLE);

    m_map1_posY = 0;
    m_map2_posY = -GAME_HEIGHT;

    m_Timer.setInterval(10);

    m_keyUp = false;
    m_keyDown = false;
    m_keyLeft = false;
    m_keyRight = false;

    m_recorder = 0;
    m_bulletRecorder = 0;

    m_map.load(":/new/prefix1/6.png");
}

void MainScene::playGame()
{
    m_Timer.start();

    connect(&m_Timer, &QTimer::timeout, [=](){
        enemyToScene();
        updatePosition();
        collisionDetection();
        update();
    });
}

void MainScene::updatePosition()
{
    m_map1_posY += 1;
    m_map2_posY += 1;

    if(m_map1_posY >= GAME_HEIGHT) {
        m_map1_posY = -GAME_HEIGHT;
    }
    if(m_map2_posY >= GAME_HEIGHT) {
        m_map2_posY = -GAME_HEIGHT;
    }

    if(!m_hero.explosion->isPlaying) {
        if(m_keyUp && m_hero.y > 0) {
            m_hero.y -= m_hero.speed;
        }
        if(m_keyDown && m_hero.y < GAME_HEIGHT - m_hero.hero.height()) {
            m_hero.y += m_hero.speed;
        }
        if(m_keyLeft && m_hero.x > 0) {
            m_hero.x -= m_hero.speed;
        }
        if(m_keyRight && m_hero.x < GAME_WIDTH - m_hero.hero.width()) {
            m_hero.x += m_hero.speed;
        }
    }
    m_hero.updatePosition();

    m_bulletRecorder++;
    if(m_bulletRecorder >= BULLET_INTERVAL && !m_hero.explosion->isPlaying) {
        m_bulletRecorder = 0;

        for(int i = 0; i < 30; i++) {
            if(m_bullets[i].isFree) {
                m_bullets[i].isFree = false;
                m_bullets[i].x = m_hero.x + m_hero.hero.width() * 0.5 - m_bullets[i].bullet.width() * 0.5;
                m_bullets[i].y = m_hero.y - m_bullets[i].bullet.height();
                break;
            }
        }
    }

    for(int i = 0; i < 30; i++) {
        if(!m_bullets[i].isFree) {
            m_bullets[i].updatePosition();
        }
    }

    for(int i = 0; i < 30; i++) {
        if(!m_enemyBullets[i].isFree) {
            m_enemyBullets[i].updatePosition();
        }
    }

    for(int i = 0; i < 20; i++) {
        if(!m_enemys[i].isFree) {
            m_enemys[i].updatePosition();
        }
    }
}

void MainScene::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    painter.drawPixmap(0, m_map1_posY, m_map);
    painter.drawPixmap(0, m_map2_posY, m_map);

    if(!m_hero.explosion->isPlaying) {
        painter.drawPixmap(m_hero.x, m_hero.y, m_hero.hero);
    } else {
        painter.drawPixmap(m_hero.x, m_hero.y, m_hero.explosion->currentPixmap());
    }

    for(int i = 0; i < 30; i++) {
        if(!m_bullets[i].isFree) {
            painter.drawPixmap(m_bullets[i].x, m_bullets[i].y, m_bullets[i].bullet);
        }
    }

    for(int i = 0; i < 30; i++) {
        if(!m_enemyBullets[i].isFree) {
            painter.drawPixmap(m_enemyBullets[i].x, m_enemyBullets[i].y, m_enemyBullets[i].bullet);
        }
    }

    for(int i = 0; i < 20; i++) {
        if(!m_enemys[i].isFree) {
            if(!m_enemys[i].explosion->isPlaying) {
                painter.drawPixmap(m_enemys[i].x, m_enemys[i].y, m_enemys[i].enemy);
            } else {
                painter.drawPixmap(m_enemys[i].x, m_enemys[i].y,
                                   m_enemys[i].explosion->currentPixmap());
            }
        }
    }
}

void MainScene::keyPressEvent(QKeyEvent *event)
{
    switch(event->key()) {
    case Qt::Key_Up:
        m_keyUp = true;
        break;
    case Qt::Key_Down:
        m_keyDown = true;
        break;
    case Qt::Key_Left:
        m_keyLeft = true;
        break;
    case Qt::Key_Right:
        m_keyRight = true;
        break;
    case Qt::Key_Space:
        break;
    case Qt::Key_Escape:
        this->close();
        break;
    default:
        break;
    }
}

void MainScene::keyReleaseEvent(QKeyEvent *event)
{
    switch(event->key()) {
    case Qt::Key_Up:
        m_keyUp = false;
        break;
    case Qt::Key_Down:
        m_keyDown = false;
        break;
    case Qt::Key_Left:
        m_keyLeft = false;
        break;
    case Qt::Key_Right:
        m_keyRight = false;
        break;
    default:
        break;
    }
}

void MainScene::enemyToScene()
{
    m_recorder++;
    if(m_recorder < ENEMY_INTERVAL) {
        return;
    }

    m_recorder = 0;

    int type = 1;
    int random = QRandomGenerator::global()->bounded(100);
    if(random < 5) {
        type = 3;
    } else if(random < 20) {
        type = 2;
    }

    for(int i = 0; i < 20; i++) {
        if(m_enemys[i].isFree) {
            m_enemys[i].isFree = false;
            m_enemys[i].type = type;

            switch(type) {
            case 1:
                m_enemys[i].enemy.load(ENEMY1_PATH);
                m_enemys[i].explosion->loadFrames({ENEMY1_DOWN1, ENEMY1_DOWN2, ENEMY1_DOWN3, ENEMY1_DOWN4});
                m_enemys[i].speed = ENEMY1_SPEED;
                m_enemys[i].health = 1;
                break;
            case 2:
                m_enemys[i].enemy.load(ENEMY2_PATH);
                m_enemys[i].explosion->loadFrames({ENEMY2_DOWN1, ENEMY2_DOWN2, ENEMY2_DOWN3, ENEMY2_DOWN4});
                m_enemys[i].speed = ENEMY2_SPEED;
                m_enemys[i].health = 3;
                break;
            case 3:
                m_enemys[i].enemy.load(ENEMY3_PATH);
                m_enemys[i].explosion->loadFrames({ENEMY3_DOWN1, ENEMY3_DOWN2, ENEMY3_DOWN3,
                                                   ENEMY3_DOWN4, ENEMY3_DOWN5, ENEMY3_DOWN6});
                m_enemys[i].speed = ENEMY3_SPEED;
                m_enemys[i].health = 5;
                break;
            }

            m_enemys[i].x = QRandomGenerator::global()->bounded(0, GAME_WIDTH - m_enemys[i].enemy.width());
            m_enemys[i].y = -m_enemys[i].enemy.height();
            break;
        }
    }
}

void MainScene::collisionDetection()
{
    for(int i = 0; i < 30; i++) {
        if(m_bullets[i].isFree) continue;

        for(int j = 0; j < 20; j++) {
            if(m_enemys[j].isFree || m_enemys[j].explosion->isPlaying) continue;

            if(m_bullets[i].x > m_enemys[j].x &&
                m_bullets[i].x < m_enemys[j].x + m_enemys[j].enemy.width() &&
                m_bullets[i].y > m_enemys[j].y &&
                m_bullets[i].y < m_enemys[j].y + m_enemys[j].enemy.height()) {

                m_enemys[j].health--;
                m_bullets[i].isFree = true;

                if(m_enemys[j].health <= 0) {
                    m_enemys[j].down();
                }

                break;
            }
        }
    }

    if(!m_hero.explosion->isPlaying) {
        for(int i = 0; i < 20; i++) {
            if(m_enemys[i].isFree || m_enemys[i].explosion->isPlaying) continue;

            if(m_hero.x + m_hero.hero.width() > m_enemys[i].x &&
                m_hero.x < m_enemys[i].x + m_enemys[i].enemy.width() &&
                m_hero.y + m_hero.hero.height() > m_enemys[i].y &&
                m_hero.y < m_enemys[i].y + m_enemys[i].enemy.height()) {

                m_hero.down();
                m_enemys[i].down();
                break;
            }
        }
    }
}
void MainScene::addBullet(Bullet* bullet)
{
    for(int i = 0; i < 30; i++) {
        if(m_bullets[i].isFree) {
            m_bullets[i] = *bullet;
            m_bullets[i].isFree = false;
            break;
        }
    }
}
